#include "bsp.h"
#include "usb_config.h"

#include "udisk_effect.h"

uint8_t is_usb_connected = 1;


static void ff_check_disk (void);
static int usbd_init(void);
static void ff_print_err (FRESULT f_res);

static FRESULT ff_count_rhd_files (uint8_t *count);

FATFS fs;
FIL file;
FRESULT f_res;
UINT bw;
UINT br;
char file_title[20] = {0};
uint8_t file_type = 0;

BYTE work[4096];
struct dccfxplayer color;

// 分区数量，通过读取文件数量来判定
uint8_t rhd_files = 20;


struct dccfxplayer color;

void ff_run_err_act (void);
void ff_close_end (void);
int ff_read_frame_data (struct dccfxplayer *pl);
int ff_read_zone_params (struct dccfxplayer *pl);
void ff_send_fram_data (struct dccfxplayer *pl);
void ff_close_end (void);


void udisk_effect_init (void)
{
    if (SD_Initialize() != 0)
    {
        printf("load sd nand error\r\n");
    }
    usbd_init();
    ws2812_turn_off_all();
    dccfxplayer_init (&color,
                      led_rgb_data,
                      ff_read_zone_params,
                      ff_read_frame_data,
                      ff_send_fram_data,
                      ff_close_end,
                      ws2812_turn_off_all,
                      ff_run_err_act,
                      5);
    color.curr_zone = 1;
    dccfxplayer_start (&color, color.curr_zone);
    
    ff_check_disk();
    ff_count_rhd_files (&rhd_files);
    printf("rhd files:%d\r\n", rhd_files);
    
}



void udisk_effect_task (void)
{
    if (is_usb_connected == 1)
    {
        return ;
    }
    dccfxplayer_state_poll (&color);  
}


void on_udisk_connect (void)
{
    is_usb_connected = 1;
    printf ("on connect\r\n");
}

void on_udisk_disconnect (void)
{
    printf ("on disconn\r\n");
    is_usb_connected = 0;   
}




/**
 * @brief 检查文件名是否以.RHD扩展名结尾（不区分大小写）
 * @param fname 文件名
 * @return 1 表示是.RHD文件，0 表示不是
 */
static int ff_is_rhd_file (const char *fname) {
    int len = 0;
    while (fname[len] != '\0') {
        len++;
    }
    if (len < 4) {
        return 0;  // 文件名太短，不可能是.RHD
    }
    const char *ext = fname + len - 4;
    if (ext[0] != '.') {
        return 0;            // 没有扩展名或格式不对
    }
    char r = ext[1] | 0x20;  // 转换为小写
    char h = ext[2] | 0x20;
    char d = ext[3] | 0x20;
    return (r == 'r' && h == 'h' && d == 'd');
}

/**
 * @brief 查找根目录下扩展名为.RHD的文件数量
 * @param count 指向存储文件数量的指针
 * @return FRESULT 返回FATFS操作结果
 */
FRESULT ff_count_rhd_files (uint8_t *count) {
    FRESULT fr;   // FATFS操作结果
    DIR dir;      // 目录对象
    FILINFO fno;  // 文件信息

    *count = 0;   // 初始化计数器

    // 打开根目录
    fr = f_opendir (&dir, "0:/");
    if (fr != FR_OK) {
        return fr;  // 打开失败
    }

    // 遍历目录
    while (1) {
        fr = f_readdir (&dir, &fno);
        if (fr != FR_OK) {
            break;  // 读取失败，退出
        }
        if (fno.fname[0] == 0) {
            break;  // 目录末尾，退出
        }

        // 检查是否是主文件（非B开头）且扩展名为.RHD
        if (fno.fname[0] != 'B' && ff_is_rhd_file (fno.fname)) {
            (*count)++;  // 找到主.RHD文件，计数加1
        }
    }

    // 关闭目录
    f_closedir (&dir);
    return fr;
}


int ff_read_zone_params (struct dccfxplayer *pl) {

    int rsl = 0;
    FILINFO fno;

    sprintf (file_title, "0:/%d.RHD", pl->curr_zone);

    // printf ("%s\n", file_title);

    ff_count_rhd_files (&rhd_files);
    // printf ("read zone find %d rhd files\r\n", zone_count);

//    f_res = f_mount (&fs, "0:", 1);
//    if (f_res != FR_OK) {
//        rsl = 1;
//        goto exit;
//    }

    f_res = f_open (&file, file_title, FA_READ | FA_OPEN_EXISTING);
    if (f_res != FR_OK) {
        rsl = 2;
        printf ("%s\r\n", file_title);
        goto exit;
    }
    FIL fil;
    DWORD file_size = f_size(&fil);  // 获取文件大小（字节数）
    printf("文件大小: %lu 字节\n", file_size);  
//    printf("read start\r\n");
    f_res = f_read (&file, pl->p_read_buffer, 30, &br);
    if (f_res != FR_OK) {
        rsl = 3;
    }
//    printf("read ok\r\n");
    
    f_res = f_close (&file);
exit:
    if (rsl) {
        printf ("params, ret: %d\r\n", rsl);
        ff_print_err (f_res);
    } 
    return rsl;
}

#define SECTOR_SIZE 512 // 定义扇区大小，需与 SD NAND 匹配
int ff_read_frame_data (struct dccfxplayer *pl) {

    int rsl = 0;
    pl->read_addr_curr = 30 + pl->frame_size * pl->curr_frame;

    f_res = f_lseek (&file, pl->read_addr_curr);
    if (f_res != FR_OK) {
        rsl = 1;
        goto exit;
    }

    f_res = f_read (&file, pl->p_read_buffer, pl->frame_size, &br);
    if (f_res != FR_OK) {
        rsl = 2;
        goto exit;
    }
exit:
    return rsl;
}

void ff_send_fram_data (struct dccfxplayer *pl) {
    uint8_t *original_data = pl->p_read_buffer + 3;
    
    ws2812_data_encode_spi(original_data, pl->led_count);
    ws2812_send_data_spi(pl->led_count * 12);
}



void ff_close_end (void) {
    printf ("end close file\r\n");
    f_res = f_close (&file);
}

void ff_run_err_act (void) {
    ws2812_turn_off_all();
    printf ("err!\r\n");
}




static void ff_print_err (FRESULT f_res) {
    switch (f_res) {
    case FR_OK: printf ("FR_OK\r\n"); break;
    case FR_DISK_ERR: printf ("FR_DISK_ERR\r\n"); break;
    case FR_INT_ERR: printf ("FR_INT_ERR\r\n"); break;
    case FR_NOT_READY: printf ("FR_NOT_READY\r\n"); break;
    case FR_NO_FILE: printf ("FR_NO_FILE\r\n"); break;
    case FR_NO_PATH: printf ("FR_NO_PATH\r\n"); break;
    case FR_INVALID_NAME: printf ("FR_INVALID_NAME\r\n"); break;
    case FR_DENIED: printf ("FR_DENIED\r\n"); break;
    case FR_EXIST: printf ("FR_EXIST\r\n"); break;
    case FR_INVALID_OBJECT: printf ("FR_INVALID_OBJECT\r\n"); break;
    case FR_WRITE_PROTECTED: printf ("FR_WRITE_PROTECTED\r\n"); break;
    case FR_INVALID_DRIVE: printf ("FR_INVALID_DRIVE\r\n"); break;
    case FR_NOT_ENABLED: printf ("FR_NOT_ENABLED\r\n"); break;
    case FR_NO_FILESYSTEM: printf ("FR_NO_FILESYSTEM\r\n"); break;
    case FR_MKFS_ABORTED: printf ("FR_MKFS_ABORTED\r\n"); break;
    case FR_TIMEOUT: printf ("FR_TIMEOUT\r\n"); break;
    case FR_LOCKED: printf ("FR_LOCKED\r\n"); break;
    case FR_NOT_ENOUGH_CORE: printf ("FR_NOT_ENOUGH_CORE\r\n"); break;
    case FR_TOO_MANY_OPEN_FILES: printf ("FR_TOO_MANY_OPEN_FILES\r\n"); break;
    case FR_INVALID_PARAMETER: printf ("FR_INVALID_PARAMETER\r\n"); break;
    default: printf ("Other error codes!\r\n");
    }
}

static void ff_check_disk (void) {
    f_res = f_mount (&fs, "0:", 1);
    if (f_res == FR_NO_FILESYSTEM) {
        printf ("Formatting...\r\n");
//        f_res = f_mkfs ("0:", 0, work, 4096);
        f_res = f_mkfs ("0:", 0, 512);
        if (f_res == FR_OK) {
            printf ("Formatting success!\r\n");
            f_res = f_mount (NULL, "0:", 1);
            f_res = f_mount (&fs, "0:", 1);
        } else {
            printf ("Formatting fail!\r\n");
            ff_print_err (f_res);
        }
    } else if (f_res != FR_OK) {
        printf ("Mount fail!\r\n");
        ff_print_err (f_res);
    } else {
        printf ("Mount success!\r\n");
    }
}

static int usbd_init(void)
{
    /* usb select the HSI48M clock */
    LL_RCC_HSI48_Enable();
    LL_RCC_SetUSBClockSource(LL_RCC_USB_CLKSOURCE_HSI48);
    LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_USB);

    msc_ram_init();

    /* Enable USB interrupt */
    NVIC_EnableIRQ(USBD_IRQn);
    NVIC_SetPriority(USBD_IRQn, 0);

    return 0;
}
